package com.dongzili.common.controller;


import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dongzili.common.mybatisplus.MybatisPlusUtil;
import com.dongzili.common.utils.ReflectUtils;
import com.dongzili.common.vo.OrderType;
import com.dongzili.common.vo.OrderVo;
import com.dongzili.common.vo.PageRequest;
import com.dongzili.common.vo.R;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

public class BaseController<T> {

    private final Class<T> tClass;
    protected BaseMapper<T> baseMapper;
    public BaseController(){
        this.tClass = resolveEntityClass();
        DS ds = tClass.getAnnotation(DS.class);
        if (ds != null){
            DynamicDataSourceContextHolder.push(ds.value());
        }else{
            DynamicDataSourceContextHolder.push("main");
        }
        baseMapper = MybatisPlusUtil.getMapper(this.tClass);
    }
    /** 列表查询 */
    @PostMapping("/list")
    public R<List<T>> list(@RequestBody PageRequest<T> request) {
        QueryWrapper<T> query = new QueryWrapper<>(request.getEntity());
        // like 字段用 or 连接
        Map<String, Object> fieldValueMap = ReflectUtils.getNotNullFieldValueMap(request.getLikeEntity());
        if (!fieldValueMap.isEmpty()){
            query.and(m -> {
                fieldValueMap.forEach((k, v)->{
                    if(v instanceof String){
                        m.or().like(k, v);
                    } else if (v instanceof List){
                        for (Object o : (List<?>) v) {
                            m.or().like(k, o);
                        }
                    }
                });
            });
        }

        // 排序字段
        addOrderByCondition(request, query);

        IPage<T> pageData = MybatisPlusUtil.getMapper(this.tClass).selectPage(new Page<>(request.getCurrent(), request.getSize()), query);
        return R.success(pageData.getRecords(), pageData.getTotal());
    }

    /** 添加 */
    @PostMapping("/add")
    public R<Integer> add(@RequestBody T entity){
        if(MybatisPlusUtil.getMapper(this.tClass).insert(entity) > 0){
            return R.success();
        }
        return R.error();
    }

    /** 更新 */
    @PostMapping("/update")
    public R<Integer> update(@RequestBody T entity){
        if(MybatisPlusUtil.getMapper(this.tClass).updateById(entity) > 0){
            return R.success();
        }
        return R.error();
    }

    /** 根据id删除 */
    @GetMapping("/delete/{id}")
    public R<Integer> delete(@PathVariable("id") Integer id){
        if(MybatisPlusUtil.getMapper(this.tClass).deleteById(id) > 0){
            return R.success();
        }
        return R.error();
    }
    /** 根据id查询 */
    @GetMapping("/get/{id}")
    public R<T> get(@PathVariable("id") Integer id){
        return R.success(MybatisPlusUtil.getMapper(this.tClass).selectById(id));
    }

    private Class<T> resolveEntityClass() {
        Type superClass = getClass().getGenericSuperclass();
        if (superClass instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) superClass;
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            return (Class<T>) actualTypeArguments[0];
        }
        throw new IllegalArgumentException("Class is not parameterized with generic types");
    }

    /**
     * 添加排序条件
     */
    private static <T> void addOrderByCondition(PageRequest<T> request, QueryWrapper<T> queryWrapper) {
        if(request.getOrders()!=null && !request.getOrders().isEmpty()){
            for (OrderVo orderVo : request.getOrders()){
                if(OrderType.Desc.equals(orderVo.getOrderType())){
                    queryWrapper.orderByDesc(orderVo.getFiledName());
                }else{
                    queryWrapper.orderByAsc(orderVo.getFiledName());
                }
            }
        }
    }

}
